<!DOCTYPE html>
<html lang="en"><head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1"><!-- Begin Jekyll SEO tag v2.8.0 -->
<title>0068: MVC XI - Multi-level TreeStore | gtkDcoding</title>
<meta name="generator" content="Jekyll v4.3.4" />
<meta property="og:title" content="0068: MVC XI - Multi-level TreeStore" />
<meta name="author" content="Ron Tarrant" />
<meta property="og:locale" content="en_US" />
<meta name="description" content="GTK Tutorial covering a multi-level, multi-column TreeStore implemented as a model for a TreeView." />
<meta property="og:description" content="GTK Tutorial covering a multi-level, multi-column TreeStore implemented as a model for a TreeView." />
<link rel="canonical" href="http://localhost:4000/posts/0068-multi-level-treestore.html" />
<meta property="og:url" content="http://localhost:4000/posts/0068-multi-level-treestore.html" />
<meta property="og:site_name" content="gtkDcoding" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2019-09-06T00:00:00-04:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="0068: MVC XI - Multi-level TreeStore" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"Ron Tarrant"},"dateModified":"2019-09-06T00:00:00-04:00","datePublished":"2019-09-06T00:00:00-04:00","description":"GTK Tutorial covering a multi-level, multi-column TreeStore implemented as a model for a TreeView.","headline":"0068: MVC XI - Multi-level TreeStore","mainEntityOfPage":{"@type":"WebPage","@id":"http://localhost:4000/posts/0068-multi-level-treestore.html"},"url":"http://localhost:4000/posts/0068-multi-level-treestore.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="stylesheet" href="../assets/main.css">
  <link rel="stylesheet" href="../css/style.css" /><link type="application/atom+xml" rel="alternate" href="http://localhost:4000/feed.xml" title="gtkDcoding" /></head>
<body><header class="site-header" role="banner">

  <div class="wrapper"><a class="site-title" rel="author" href="../">gtkDcoding</a><nav class="site-nav">
        <input type="checkbox" id="nav-trigger" class="nav-trigger" />
        <label for="nav-trigger">
          <span class="menu-icon">
            <svg viewBox="0 0 18 15" width="18px" height="15px">
              <path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"/>
            </svg>
          </span>
        </label>

        <div class="trigger"><a class="page-link" href="../about.html">About</a><a class="page-link" href="../index-reverse.html">Posts in Date Order</a><a class="page-link" href="../topics.html">Blog Posts by Topic</a></div>
      </nav></div>
</header>
<main class="page-content" aria-label="Content">
      <div class="wrapper">
        <article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
	<header class="post-header">
		<link rel="stylesheet" href="../css/font_size.css" />
		<link rel="stylesheet" href="../css/figure.css" />
		<link rel="stylesheet" href="../css/topics/mvc.css" />  <!-- sub in the tag/topic -->
		<link rel="stylesheet" href="../css/modal.css" />
		<link rel="stylesheet" href="../css/post.css" />
		<link rel="stylesheet" href="../css/mascot_effects.css" />

		
		
		<p class="post-meta">
		<time class="dt-published" datetime="2019-09-06T00:00:00-04:00" itemprop="datePublished">Friday, September 6, 2019
		</time>• by <span itemprop="author" itemscope itemtype="http://schema.org/Person"><span class="p-author h-card" itemprop="name">Ron Tarrant</span></span></p>
	</header>

	<div class="post-content e-content" itemprop="articleBody">
		<div class="skew-line"></div>
		<h1 id="0068-mvc-xi---multi-level-treestore">0068: MVC XI - Multi-level TreeStore</h1>

<p>The last time we looked at an <strong>MVC</strong> example, we dug into the basics of the <code class="language-plaintext highlighter-rouge">TreeStore</code>, but we didn’t look at how it deals with multi-level, multi-column data. Today we pick up where we left off and do just that.</p>

<p><em>Note: The example used herein is based heavily on the D-language <code class="language-plaintext highlighter-rouge">TreeStore</code> example found on a <a href="https://sites.google.com/site/gtkdtutorial#chapter6">Google Sites page</a> built back in 2013. I could find no credits, so to the anonymous writer of that tutorial, I thank you.</em></p>

<h2 id="a-multi-level-treestore">A Multi-level TreeStore</h2>

<!-- 0, 1 -->
<!-- first occurrence of application and terminal screen shots on a single page -->
<div class="screenshot-frame">
	<div class="frame-header">
		Results of this example:
	</div>
	<div class="frame-screenshot">
		<figure>
			<img id="img0" src="../images/screenshots/017_mvc/mvc_18.png" alt="Current example output" />		<!-- img# -->
			
			<!-- Modal for screenshot -->
			<div id="modal0" class="modal">																	<!-- modal# -->
				<span class="close0">&times;</span>															<!-- close# -->
				<img class="modal-content" id="img00" />															<!-- img## -->
				<div id="caption"></div>
			</div>
			
			<script>
			// Get the modal
			var modal = document.getElementById("modal0");														// modal#
			
			// Get the image and insert it inside the modal - use its "alt" text as a caption
			var img = document.getElementById("img0");															// img#
			var modalImg = document.getElementById("img00");													// img##
			var captionText = document.getElementById("caption");

			img.onclick = function()
			{
			  modal.style.display = "block";
			  modalImg.src = this.src;
			  captionText.innerHTML = this.alt;
			}
			
			// Get the <span> element that closes the modal
			var span = document.getElementsByClassName("close0")[0];											// close#
			
			// When the user clicks on <span> (x), close the modal
			span.onclick = function()
			{ 
				modal.style.display = "none";
			}
			</script>
			<figcaption>
			Current example output
			</figcaption>
		</figure>
	</div>

	<div class="frame-terminal">
		<figure class="right">
			<img id="img1" src="../images/screenshots/017_mvc/mvc_18_term.png" alt="Current example terminal output" />		<!-- img#, filename -->

			<!-- Modal for terminal shot -->
			<div id="modal1" class="modal">																				<!-- modal# -->
				<span class="close1">&times;</span>																		<!-- close# -->
				<img class="modal-content" id="img11" />																		<!-- img## -->
				<div id="caption"></div>
			</div>
			
			<script>
			// Get the modal
			var modal = document.getElementById("modal1");																	// modal#
			
			// Get the image and insert it inside the modal - use its "alt" text as a caption
			var img = document.getElementById("img1");																		// img#
			var modalImg = document.getElementById("img11");																// img##
			var captionText = document.getElementById("caption");

			img.onclick = function()
			{
			  modal.style.display = "block";
			  modalImg.src = this.src;
			  captionText.innerHTML = this.alt;
			}
			
			// Get the <span> element that closes the modal
			var span = document.getElementsByClassName("close1")[0];														// close#
			
			// When the user clicks on <span> (x), close the modal
			span.onclick = function()
			{ 
				modal.style.display = "none";
			}
			</script>

			<figcaption>
				Current example terminal output (click for enlarged view)
			</figcaption>
		</figure>
	</div>

	<div class="frame-footer">																								<!-- ------------- filename (below) --------- -->
		The code file for this example is available <a href="https://github.com/rontarrant/gtkd_demos/blob/master/017_mvc/mvc_18_multi_level_treestore.d" target="_blank">here</a>.
	</div>
</div>
<!-- end of snippet for first (1st) occurrence of application and terminal screen shots on a single page -->

<h3 id="the-model">The Model</h3>

<p>The heart of this example is the <code class="language-plaintext highlighter-rouge">LocationTreeStore</code> where we set up a three-tier hierarchy of population numbers for some of the continents, countries, and cities on our planet. The procedure is more or less the same as what we’ve done before except that some of the work is farmed out to the <code class="language-plaintext highlighter-rouge">addLocation()</code> function… which we’ll look at momentarily.</p>

<p>In the original 2013 example, there were two functions for adding locations:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">addLocation</code>, and</li>
  <li><code class="language-plaintext highlighter-rouge">addChildLocation</code>.</li>
</ul>

<p>But I wanted to bring a little something to the table, so I reworked them as a single, overloaded function called simply <code class="language-plaintext highlighter-rouge">addLocation()</code>. And while I was at it, I also added pretty-ish formatting to the numbers. Here’s how it all goes down:</p>

<p>First, we declare the variables:</p>

<div class="language-d highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">private</span><span class="p">:</span>
<span class="n">TreeIter</span> <span class="n">parentIterAsia</span><span class="p">,</span> <span class="n">childIterChina</span><span class="p">,</span> <span class="n">childIterJapan</span><span class="p">;</span>
<span class="n">TreeIter</span> <span class="n">parentIterEurope</span><span class="p">,</span> <span class="n">childIterUK</span><span class="p">,</span> <span class="n">childIterFrance</span><span class="p">;</span>
<span class="n">TreeIter</span> <span class="n">parentIterNorthAmerica</span><span class="p">,</span> <span class="n">childIterCanada</span><span class="p">,</span> <span class="n">childIterUSA</span><span class="p">;</span>
</code></pre></div></div>

<p>Then in the constructor, we lay out the Model:</p>

<div class="language-d highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">super</span><span class="p">([</span><span class="n">GType</span><span class="p">.</span><span class="n">STRING</span><span class="p">,</span> <span class="n">GType</span><span class="p">.</span><span class="n">STRING</span><span class="p">]);</span>
</code></pre></div></div>

<p>Following which, we populate each hierarchy of continent, country, and city like this:</p>

<div class="language-d highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">parentIterNorthAmerica</span> <span class="p">=</span> <span class="n">addLocation</span><span class="p">(</span><span class="s">"North America"</span><span class="p">,</span> <span class="k">cast</span><span class="p">(</span><span class="kt">uint</span><span class="p">)</span><span class="mi">366_496_802</span><span class="p">);</span>
<span class="n">childIterCanada</span> <span class="p">=</span> <span class="n">addLocation</span><span class="p">(</span><span class="n">parentIterNorthAmerica</span><span class="p">,</span> <span class="s">"Canada"</span><span class="p">,</span> <span class="k">cast</span><span class="p">(</span><span class="kt">uint</span><span class="p">)</span><span class="mi">37_307_925</span><span class="p">);</span>
<span class="n">addLocation</span><span class="p">(</span><span class="n">childIterCanada</span><span class="p">,</span> <span class="s">"Ottawa"</span><span class="p">,</span> <span class="k">cast</span><span class="p">(</span><span class="kt">uint</span><span class="p">)</span><span class="mi">1_378_151</span><span class="p">);</span>
<span class="n">childIterUSA</span> <span class="p">=</span> <span class="n">addLocation</span><span class="p">(</span><span class="n">parentIterNorthAmerica</span><span class="p">,</span> <span class="s">"United States"</span><span class="p">,</span> <span class="k">cast</span><span class="p">(</span><span class="kt">uint</span><span class="p">)</span><span class="mi">329_293_776</span><span class="p">);</span>
<span class="n">addLocation</span><span class="p">(</span><span class="n">childIterUSA</span><span class="p">,</span> <span class="s">"Washington, DC"</span><span class="p">,</span> <span class="k">cast</span><span class="p">(</span><span class="kt">uint</span><span class="p">)</span><span class="mi">713_244</span><span class="p">);</span>
</code></pre></div></div>

<p>Note that the numbers are all cast as <code class="language-plaintext highlighter-rouge">uint</code> types at this stage.</p>

<h3 id="the-overloaded-function">The Overloaded Function</h3>

<p>Here are the two overloads:</p>

<div class="language-d highlighter-rouge"><div class="highlight"><pre class="highlight"><code>	<span class="c1">// Adds a location and returns the TreeIter of the item added.</span>
	<span class="k">public</span> <span class="n">TreeIter</span> <span class="n">addLocation</span><span class="p">(</span><span class="k">in</span> <span class="nb">string</span> <span class="n">name</span><span class="p">,</span> <span class="k">in</span> <span class="kt">uint</span> <span class="n">population</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">TreeIter</span> <span class="n">iter</span> <span class="p">=</span> <span class="n">createIter</span><span class="p">();</span>
		<span class="n">setValue</span><span class="p">(</span><span class="n">iter</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">name</span><span class="p">);</span>
		<span class="n">setValue</span><span class="p">(</span><span class="n">iter</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">format</span><span class="p">(</span><span class="s">"%,?d"</span><span class="p">,</span> <span class="sc">','</span><span class="p">,</span> <span class="n">population</span><span class="p">));</span>
		
		<span class="k">return</span><span class="p">(</span><span class="n">iter</span><span class="p">);</span>
		
	<span class="p">}</span> <span class="c1">// addLocation()</span>
	

	<span class="c1">// Adds a child location to the specified parent TreeIter.</span>
	<span class="k">public</span> <span class="n">TreeIter</span> <span class="n">addLocation</span><span class="p">(</span><span class="n">TreeIter</span> <span class="n">parent</span><span class="p">,</span> <span class="k">in</span> <span class="nb">string</span> <span class="n">name</span><span class="p">,</span> <span class="k">in</span> <span class="kt">uint</span> <span class="n">population</span><span class="p">)</span>
	<span class="p">{</span>
		<span class="n">TreeIter</span> <span class="n">childIter</span> <span class="p">=</span> <span class="n">createIter</span><span class="p">(</span><span class="n">parent</span><span class="p">);</span>
		<span class="n">setValue</span><span class="p">(</span><span class="n">childIter</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">name</span><span class="p">);</span>
		<span class="n">setValue</span><span class="p">(</span><span class="n">childIter</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">format</span><span class="p">(</span><span class="s">"%,?d"</span><span class="p">,</span> <span class="sc">','</span><span class="p">,</span> <span class="n">population</span><span class="p">));</span>
		
		<span class="k">return</span><span class="p">(</span><span class="n">childIter</span><span class="p">);</span>
		
	<span class="p">}</span> <span class="c1">// addLocation()</span>
</code></pre></div></div>

<p>The first overload deals with top-tier rows. It needs two arguments, a string for the name of the continent and a <code class="language-plaintext highlighter-rouge">uint</code> for the population. And it returns a <code class="language-plaintext highlighter-rouge">TreeIter</code>.</p>

<p>The second overload has three arguments, a <code class="language-plaintext highlighter-rouge">TreeIter</code> for the parent that’ll “be the boss of” the child we’re creating, a string for the child’s name, and, of course, a <code class="language-plaintext highlighter-rouge">uint</code>.</p>

<p><em>Note: When doing overloaded functions, make sure each overload’s first argument is of a unique type (uint, string, etc.) so the D compiler can easily differentiate between them.</em></p>

<h2 id="the-view">The View</h2>

<p>Structurally, the view is no different than what we used in the earlier <code class="language-plaintext highlighter-rouge">TreeStore</code> example:</p>

<div class="language-d highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="n">LocationTreeView</span> <span class="p">:</span> <span class="n">TreeView</span>
<span class="p">{</span>
	<span class="k">private</span><span class="p">:</span>
	<span class="n">TreeViewColumn</span> <span class="n">countryColumn</span><span class="p">,</span> <span class="n">populationColumn</span><span class="p">;</span>
	<span class="n">LocationTreeStore</span> <span class="n">locationTreeStore</span><span class="p">;</span>
	
	<span class="k">public</span><span class="p">:</span>
	<span class="k">this</span><span class="p">()</span>
	<span class="p">{</span>
		<span class="k">super</span><span class="p">();</span>
		<span class="n">locationTreeStore</span> <span class="p">=</span> <span class="k">new</span> <span class="n">LocationTreeStore</span><span class="p">();</span>
		<span class="n">setModel</span><span class="p">(</span><span class="n">locationTreeStore</span><span class="p">);</span>

		<span class="c1">// Add Country Column</span>
		<span class="n">countryColumn</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TreeViewColumn</span><span class="p">(</span><span class="s">"Location"</span><span class="p">,</span> <span class="k">new</span> <span class="n">CellRendererText</span><span class="p">(),</span> <span class="s">"text"</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
		<span class="n">appendColumn</span><span class="p">(</span><span class="n">countryColumn</span><span class="p">);</span>
		
		<span class="c1">// Add Capital Column</span>
		<span class="n">populationColumn</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TreeViewColumn</span><span class="p">(</span><span class="s">"Population"</span><span class="p">,</span> <span class="k">new</span> <span class="n">CellRendererText</span><span class="p">(),</span> <span class="s">"text"</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
		<span class="n">appendColumn</span><span class="p">(</span><span class="n">populationColumn</span><span class="p">);</span>

	<span class="p">}</span> <span class="c1">// this()</span>
	
<span class="p">}</span> <span class="c1">// class LocationTreeView</span>
</code></pre></div></div>

<p>We simply:</p>

<ul>
  <li>instantiate the <code class="language-plaintext highlighter-rouge">TreeView</code>,</li>
  <li>associate the model (<code class="language-plaintext highlighter-rouge">LocationTreeStore</code>), and</li>
  <li>pop in the <code class="language-plaintext highlighter-rouge">TreeViewColumn</code>s.</li>
</ul>

<h3 id="imports">Imports</h3>

<p>The only other thing we need to do—and this, only because I wanted to prettify the numbers—is to do one extra import statement:</p>

<div class="language-d highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="n">std</span><span class="p">.</span><span class="nb">string</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="conclusion">Conclusion</h2>

<p>All this <code class="language-plaintext highlighter-rouge">TreeView</code>/<code class="language-plaintext highlighter-rouge">TreeStore</code> stuff is rather easy once we’ve broken it all down. Yes, there’s a lot involved, but none of it’s really a brain bender when we approach it one concept at a time.</p>

<p>Hope you liked the <strong>MVC</strong> series. Until next time, have fun coding.</p>

<div class="blog-nav">
	<div style="float: left;">
		<a href="./0067-mvc-xii-expander.html">Previous: MVC - Expander</a>
	</div>
	<div style="float: right;">
		<a href="./0069-textview-and-textbuffer.html">Next: TextView and TextBuffer</a>
	</div>
</div>
<p>
	<h3></h3>
<div class="inpage-frame">
	<a href="https://github.com/sponsors/rontarrant">
		<BR>
		<BR>
		<B>Is this article useful? Educational? Entertaining, perhaps?</B>
		<BR>
		<figure class="left">
			<img src="../images/favorite_32.png" alt="Sponsorship heart" style="width: 32px; height: 32px;">
		</figure>
		You're free to accept or decline this invitation to become our newest sponsor.
	</a>
</div>
	<h4 class="comment-blurb"><B>Comments? Questions? Observations?</B></h4>
	<p>
		Did we miss a tidbit of information that would make this post even more informative? Let's talk about it in the comments.
	</p>
	<script src="https://utteranc.es/client.js"
		repo="rontarrant"
		issue-term="pathname"
		theme="github-light"
		crossorigin="anonymous"
		async>
	</script>
	<ul>
		<li> come on over to the <a href="https://forum.dlang.org/">D Language Forum</a> and look for one of the <i>gtkDcoding</i> announcement posts, </li>
		<li> drop by <a href="https://forum.gtkd.org/">the <i>GtkD Forum</i></a>,</li>
		<li> follow the link below to email me, or</li>
		<li> go to the	<a href="https://www.facebook.com">gtkDcoding Facebook page.</a></li>
	</ul>
</p>
<p> You can also subscribe <a href="/feed.xml">via RSS</a> so you won't miss anything. Thank you very much for dropping by.</p>
<p>&copy; Copyright 2025 Ron Tarrant </p>
</div>

	<a class="u-url" href="./0068-multi-level-treestore.html" hidden></a>
</article>

      </div>
    </main><footer class="site-footer h-card">
  <data class="u-url" href="/"></data>

  <div class="wrapper">

    <h2 class="footer-heading">gtkDcoding</h2>

    <div class="footer-col-wrapper">
      <div class="footer-col footer-col-1">
        <ul class="contact-list">
          <li class="p-name">Ron Tarrant</li><li><a class="u-email" href="mailto:gtkDcoding@gmail.com">gtkDcoding@gmail.com</a></li></ul>
      </div>

      <div class="footer-col footer-col-2"><ul class="social-media-list"><li><a href="https://github.com/rontarrant"><svg class="svg-icon"><use xlink:href="../assets/minima-social-icons.svg#github"></use></svg> <span class="username">rontarrant</span></a></li></ul>
</div>

      <div class="footer-col footer-col-3">
        <p>Simple examples of how to use GtkD to build GUI applications.</p>
      </div>
    </div>

  </div>

</footer>
</body>

</html>
